package com.ynet.middleground.contract.model;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ynet.core.common.BaseReqObj;
import com.ynet.core.exception.BusinessException;
import com.ynet.middleground.contract.bean.*;
import com.ynet.middleground.contract.constant.SystemConsts;
import com.ynet.middleground.contract.constant.TemplateParamTypeEnum;
import com.ynet.middleground.contract.constant.TemplateStatusEnum;
import com.ynet.middleground.contract.dao.TemplateParamMapper;
import com.ynet.middleground.contract.dto.TemplateParamDTO;
import com.ynet.middleground.contract.dto.TemplateTableParamDTO;
import com.ynet.middleground.contract.entity.Template;
import com.ynet.middleground.contract.entity.TemplateParam;
import com.ynet.middleground.contract.entity.TemplateTableParam;
import com.ynet.middleground.contract.utils.BeanUtil;
import com.ynet.middleground.contract.utils.EnumUtil;

/**
 * @author liulx
 * @description 模板参数业务实现类
 * @date 2020-03-18 19:32
 */
@Component
public class TemplateParamModel extends ServiceImpl<TemplateParamMapper, TemplateParam> {

    @Autowired
    private Mapper mapper;

    @Autowired
    private TemplateModel templateModel;

    @Autowired
    private TemplateTableParamModel templateTableParamModel;

    @Autowired
    private UserCenterModel userCenterModel;

    /**
     * 根据模板ID查询该模板参数列表信息
     *
     * @param req 查询模板参数请求类
     * @return 模板参数列表
     */
    public List<TemplateParamDTO> queryTemplateParamsByTemplateId(QueryTemplateParamsReq req) {
        Template template = templateModel.getById(req.getTemplateId());
        Optional.ofNullable(template).orElseThrow(() -> new BusinessException("合约模板不存在", "ECCT0100"));
        if (template.getIsDeleted()) {
            throw new BusinessException("无效的合约模板", "ECCT0113");
        }

        // // 若上送业态 id，则查询业态是否有效
        // if (null != req.getFormatId()) {
        // userCenterModel.getFormatOrgInfo(req.getFormatId(), req);
        // }
        // 跨渠道访问交由内管控制 不由渠道端自行控制 by yangbh in 20200708 start
        /*if (!SystemConsts.CHANNEL_INTERNAL_MANAGEMENT.equals(req.getChannel())) {
            if (!template.getChannel().equals(req.getChannel())) {
                throw new BusinessException("当前操作渠道与数据添加渠道不一致", "ECCT0003");
            }
        }*/
        // 跨渠道访问交由内管控制 不由渠道端自行控制 by yangbh in 20200708 end
        LambdaQueryWrapper<TemplateParam> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TemplateParam::getTemplateId, req.getTemplateId());
        queryWrapper.eq(TemplateParam::getIsDeleted, SystemConsts.NOT_DELETED);
        // if (null != req.getFormatId()) {
        // queryWrapper.eq(TemplateParam::getFormatId, req.getFormatId());
        // }
        List<TemplateParam> params = this.list(queryWrapper);
        List<TemplateParamDTO> paramsList = BeanUtil.mapList(mapper, params, TemplateParamDTO.class);
        paramsList = paramsList.stream().peek(param -> {
            if (TemplateParamTypeEnum.TABLE.getCode().equals(param.getType())) {
                List<TemplateTableParam> templateTableParams =
                    templateTableParamModel.listTemplateTableParamsByTableId(param.getId(), req, null);
                param.setTableParamList(BeanUtil.mapList(mapper, templateTableParams, TemplateTableParamDTO.class));
            }
        }).collect(Collectors.toList());
        return paramsList;
    }

    /**
     * 为指定模板添加模板参数信息，模板状态必须为 未启用或已停用 才可以新增
     *
     * @param req 新增模板参数请求类
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized void addTemplateParams(AddTemplateParamsReq req) {
        List<TemplateParamReq> params = req.getParams();
        Optional.ofNullable(params).orElseThrow(() -> new BusinessException("新增模板参数列表不能为空", "ECCT0001"));
        // 检查模板参数是否有重名
        List<String> namesList = checkRepeatParams(params);
        Template template = templateModel.getById(req.getTemplateId());
        Optional.ofNullable(template).orElseThrow(() -> new BusinessException("合约模板不存在", "ECCT0100"));
        if (template.getIsDeleted()) {
            throw new BusinessException("无效的合约模板", "ECCT0113");
        }

        // add by liwq on 20220921 start
        // 档案已关联业态，修改时却未上送业态，则不允许修改
        if (template.getFormatId() != null && req.getFormatId() == null) {
            throw new BusinessException("该模板已关联业态信息，请上送所属业态id！", "ECCT0009");
        }
        // 修改时上送的业态与档案关联业态的不一致，则不允许修改
        if (null != req.getFormatId() && !req.getFormatId().equals(template.getFormatId())) {
            throw new BusinessException("该模板关联业态信息与上送业态id不一致，请检查！", "ECCT0008");
        }
        // add by liwq on 20220921 end

        if (!TemplateStatusEnum.NOT_ACTIVATE.getCode().equals(template.getStatus())
            && !TemplateStatusEnum.DISABLED.getCode().equals(template.getStatus())) {
            throw new BusinessException("模板状态为“未启用”或“已停用”才可调整参数", "ECCT0104");
        }
        LambdaQueryWrapper<TemplateParam> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TemplateParam::getTemplateId, req.getTemplateId());
        queryWrapper.eq(TemplateParam::getIsDeleted, SystemConsts.NOT_DELETED);
        queryWrapper.in(TemplateParam::getParamName, namesList);
        List<TemplateParam> repeatParams = this.list(queryWrapper);
        if (repeatParams != null && !repeatParams.isEmpty()) {
            StringBuilder finalRepeatMsg = new StringBuilder("重复参数名：");
            repeatParams.forEach(param -> {
                finalRepeatMsg.append(param.getParamName());
                finalRepeatMsg.append("，");
            });
            finalRepeatMsg.append("请检查");
            throw new BusinessException(finalRepeatMsg.toString(), "ECCT0200");
        }
        // 校验只能存在 1 个合约编号参数和 1 个合约编号二维码参数
        TemplateParam contractNo = getContractNo(req.getTemplateId());
        TemplateParam contractNoQrCode = getContractNoQrCode(req.getTemplateId());

        // 如果是已停用状态模板，需要保存历史记录
        // 新模板 id
        Integer newTemplateId = null;
        if (TemplateStatusEnum.DISABLED.getCode().equals(template.getStatus())) {
            // 保存历史模板, 并获取产生的新模板 id
            newTemplateId = templateModel.saveHistoryRecord(req.getTemplateId(), null, req, req.getFormatId());
        }
        // 封装新增参数其余信息
        Integer finalNewTemplateId = newTemplateId;
        params.stream().map(reqParam -> {
            TemplateParam param = mapper.map(reqParam, TemplateParam.class);
            param.setTemplateId(finalNewTemplateId == null ? req.getTemplateId() : finalNewTemplateId);
            param.setChannel(template.getChannel());
            param.setCreateBy(req.getOperationUserId());
            param.setGmtCreate(LocalDateTime.now());
            param.setModifiedBy(req.getOperationUserId());
            param.setGmtModified(LocalDateTime.now());
            param.setFormatId(req.getFormatId());
            // 检查参数类型值的有效性
            checkTemplateParamData(param);
            if (TemplateParamTypeEnum.CONTRACT_NO.getCode().equals(param.getType()) && contractNo != null) {
                throw new BusinessException("合约编号参数已存在", "ECCT0204");
            }
            if (TemplateParamTypeEnum.CONTRACT_NO_QR_CODE.getCode().equals(param.getType())
                && contractNoQrCode != null) {
                throw new BusinessException("合约编号二维码参数已存在", "ECCT0205");
            }
            this.save(param);
            if (TemplateParamTypeEnum.TABLE.getCode().equals(param.getType())) {
                List<TemplateTableParamReq> tableParams = reqParam.getTableParams();
                if (tableParams != null && !tableParams.isEmpty()) {
                    List<String> nameList = templateTableParamModel.checkRepeatParams(tableParams);
                    List<TemplateTableParam> templateTableParams =
                        templateTableParamModel.convertTableParam(param.getId(), nameList, tableParams, req);
                    templateTableParamModel.saveBatch(templateTableParams);
                }
            }
            return param;
        }).collect(Collectors.toList());

        // 如果是已停用状态模板，需要保存历史记录
        if (TemplateStatusEnum.DISABLED.getCode().equals(template.getStatus())) {
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TemplateParam::getTemplateId, req.getTemplateId());
            queryWrapper.eq(TemplateParam::getIsDeleted, SystemConsts.NOT_DELETED);
            // 查询出当前模板参数信息，并产生新版本
            List<TemplateParam> sourceParamList = this.list(queryWrapper);
            sourceParamList.forEach(param -> {
                TemplateParam newParam = mapper.map(param, TemplateParam.class);
                newParam.setId(null);
                newParam.setTemplateId(finalNewTemplateId);
                newParam.setFormatId(req.getFormatId());
                this.save(newParam);
                if (TemplateParamTypeEnum.TABLE.getCode().equals(param.getType())) {
                    List<TemplateTableParam> templateTableParams =
                        templateTableParamModel.listTemplateTableParamsByTableId(param.getId(), req, req.getFormatId());
                    templateTableParams.forEach(tableParam -> {
                        TemplateTableParam newTableParam = mapper.map(tableParam, TemplateTableParam.class);
                        newTableParam.setId(null);
                        newTableParam.setTableId(newParam.getId());
                        newTableParam.setFormatId(req.getFormatId());
                        templateTableParamModel.save(newTableParam);
                    });
                }

            });
        }

        /*// 如果是已停用状态模板，需要保存历史记录
        if (TemplateStatusEnum.DISABLED.getCode().equals(template.getStatus())) {
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TemplateParam::getTemplateId, req.getTemplateId());
            queryWrapper.eq(TemplateParam::getIsDeleted, SystemConsts.NOT_DELETED);
            // 查询出当前模板参数信息，一并与新增加的参数作为最新参数列表
            List<TemplateParam> sourceParamList = this.list(queryWrapper);
            addParamList.addAll(sourceParamList);
            // 保存历史模板
            templateModel.saveHistoryRecord(req.getTemplateId(), addParamList, req);
            return;
        }
        
        boolean result = this.saveBatch(addParamList);
        if (!result) {
            throw new BusinessException("新增模板参数失败", "ECCT0201");
        }*/
    }

    /**
     * 检查模板参数是否有重名
     *
     * @param params 模板参数列表
     * @return 不重名则返回模板参数名称列表
     */
    static List<String> checkRepeatParams(List<TemplateParamReq> params) {
        List<String> namesList = params.stream().map(TemplateParamReq::getParamName).collect(Collectors.toList());
        List<String> repeatNames = BeanUtil.getDuplicateElements(namesList);
        if (repeatNames != null && !repeatNames.isEmpty()) {
            StringBuilder repeatMsg = new StringBuilder("重复参数名：");
            repeatNames.forEach(param -> {
                repeatMsg.append(param);
                repeatMsg.append("，");
            });
            repeatMsg.append("请检查");
            throw new BusinessException(repeatMsg.toString(), "ECCT0200");
        }
        return namesList;
    }

    /**
     * 根据模板参数 id 修改参数信息
     *
     * @param req 修改模板参数请求类
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateParamById(UpdateTemplateParamReq req, boolean isDelete) {
        TemplateParam templateParam = this.getById(req.getId());
        if (templateParam == null || templateParam.getIsDeleted()) {
            throw new BusinessException("模板参数不存在", "ECCT0202");
        }
        req.setIsDeleted(isDelete);
        String sourceChannel = templateParam.getChannel();
        mapper.map(req, templateParam);
        templateParam.setChannel(sourceChannel);
        // 检查参数类型值的有效性
        checkTemplateParamData(templateParam);
        // 当前模板 id 对应的模板信息
        Template template = templateModel.getById(templateParam.getTemplateId());
        Optional.ofNullable(template).orElseThrow(() -> new BusinessException("合约模板不存在", "ECCT0100"));
        // 跨渠道访问交由内管控制 不由渠道端自行控制 by yangbh in 20200708 start
        /*if (!template.getChannel().equals(req.getChannel())) {
            throw new BusinessException("当前操作渠道与数据添加渠道不一致", "ECCT0003");
        }*/
        // 跨渠道访问交由内管控制 不由渠道端自行控制 by yangbh in 20200708 end
        if (template.getIsDeleted()) {
            throw new BusinessException("无效的合约模板", "ECCT0113");
        }

        // add by liwq on 20220921 start
        // 模板已关联业态，修改时却未上送业态，则不允许修改
        if (template.getFormatId() != null && req.getFormatId() == null) {
            throw new BusinessException("该模板已关联业态信息，请上送所属业态id！", "ECCT0009");
        }
        // 修改时上送的业态与模板关联业态的不一致，则不允许修改
        if (null != req.getFormatId() && !req.getFormatId().equals(template.getFormatId())) {
            throw new BusinessException("该模板关联业态信息与上送业态id不一致，请检查！", "ECCT0008");
        }
        // add by liwq on 20220921 end

        if (!TemplateStatusEnum.NOT_ACTIVATE.getCode().equals(template.getStatus())
            && !TemplateStatusEnum.DISABLED.getCode().equals(template.getStatus())) {
            throw new BusinessException("模板状态为“未启用”或“已停用”才可调整参数", "ECCT0104");
        }
        // 判断模板参数对应模板 id 对应的模板是否与最新版本冲突，防止修改旧模板的参数
        if (TemplateStatusEnum.EXPIRE.getCode().equals(template.getStatus())) {
            throw new BusinessException("请使用当前合约模板最新版本", "ECCT0105");
        }
        LambdaQueryWrapper<TemplateParam> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TemplateParam::getTemplateId, templateParam.getTemplateId());
        queryWrapper.eq(TemplateParam::getParamName, req.getParamName());
        queryWrapper.eq(TemplateParam::getIsDeleted, SystemConsts.NOT_DELETED);
        TemplateParam existParam = this.getOne(queryWrapper);
        if (existParam != null && !existParam.getId().equals(req.getId())) {
            throw new BusinessException("重复参数名：" + req.getParamName() + "，请检查", "ECCT0200");
        }
        if (!isDelete) {
            // 校验只能存在 1 个合约编号参数和 1 个合约编号二维码参数
            TemplateParam contractNo = getContractNo(templateParam.getTemplateId());
            TemplateParam contractNoQrCode = getContractNoQrCode(templateParam.getTemplateId());
            if (TemplateParamTypeEnum.CONTRACT_NO.getCode().equals(templateParam.getType()) && contractNo != null) {
                throw new BusinessException("合约编号参数已存在", "ECCT0204");
            }
            if (TemplateParamTypeEnum.CONTRACT_NO_QR_CODE.getCode().equals(templateParam.getType())
                && contractNoQrCode != null) {
                throw new BusinessException("合约编号二维码参数已存在", "ECCT0205");
            }
        }
        // 1:如果是已停用状态模板，需要保存历史记录
        if (TemplateStatusEnum.DISABLED.getCode().equals(template.getStatus())) {
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TemplateParam::getTemplateId, templateParam.getTemplateId());
            queryWrapper.eq(TemplateParam::getIsDeleted, SystemConsts.NOT_DELETED);
            // 查询出当前模板参数信息，一并与新增加的参数作为最新参数列表
            List<TemplateParam> sourceParamList = this.list(queryWrapper);
            List<TemplateParam> newParamList = sourceParamList.stream().map(param -> {
                if (param.getId().equals(templateParam.getId())) {
                    return templateParam;
                }
                return param;
            }).collect(Collectors.toList());
            // 保存历史模板
            templateModel.saveHistoryRecord(templateParam.getTemplateId(), newParamList, req, req.getFormatId());
            return;
        }
        // 2: 不是停用状态模板
        if (!TemplateStatusEnum.DISABLED.getCode().equals(template.getStatus())) {
            // 如果是表格类型，要删除表格参数
            if (TemplateParamTypeEnum.TABLE.getCode().equals(templateParam.getType())) {
                templateTableParamModel.deleteTeplateTableParamsByTableId(templateParam.getId(), req);
            }
        }

        this.updateById(templateParam);
    }

    /**
     * 删除指定模板参数信息
     *
     * @param req 删除模板参数请求类
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteTemplateParam(DeleteTemplateParamReq req) {
        TemplateParam templateParam = this.getById(req.getId());
        Optional.ofNullable(templateParam).orElseThrow(() -> new BusinessException("模板参数不存在", "ECCT0202"));

        // add by liwq on 20220921 start
        // 模板参数已关联业态，修改时却未上送业态，则不允许修改
        if (templateParam.getFormatId() != null && req.getFormatId() == null) {
            throw new BusinessException("该模板参数已关联业态信息，请上送所属业态id！", "ECCT0009");
        }
        // 修改时上送的模板参数与模板参数关联业态的不一致，则不允许修改
        if (null != req.getFormatId() && !req.getFormatId().equals(templateParam.getFormatId())) {
            throw new BusinessException("该模板参数关联业态信息与上送业态id不一致，请检查！", "ECCT0008");
        }
        // add by liwq on 20220921 end

        UpdateTemplateParamReq updateTemplateParamReq = new UpdateTemplateParamReq();
        mapper.map(templateParam, updateTemplateParamReq);
        updateTemplateParamReq.setId(req.getId());
        updateTemplateParamReq.setChannel(req.getChannel());
        updateTemplateParamReq.setOperationUserId(req.getOperationUserId());
        updateTemplateParamReq.setTraceId(req.getTraceId());
        updateTemplateParamReq.setRequestTime(req.getRequestTime());
        updateTemplateParamReq.setIsDeleted(true);
        updateParamById(updateTemplateParamReq, true);
    }

    /**
     * 检查模板参数数据的有效性，有误则抛出异常
     *
     * @param templateParam 模板参数对象
     */
    public void checkTemplateParamData(TemplateParam templateParam) {
        String type = templateParam.getType();
        Optional<TemplateParamTypeEnum> paramTypeEnum =
            EnumUtil.getEnumObject(TemplateParamTypeEnum.class, e -> e.getCode().equals(type));
        paramTypeEnum.orElseThrow(() -> new BusinessException("模板参数类型参数值错误", "ECCT0203"));
    }

    /**
     * 根据模板 id 删除模板参数
     *
     * @param templateId 模板 id
     * @param baseReqObj 基础请求参数
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteTeplateParamsByTemplateId(Integer templateId, BaseReqObj baseReqObj) {
        LambdaQueryWrapper<TemplateParam> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TemplateParam::getTemplateId, templateId);
        queryWrapper.eq(TemplateParam::getIsDeleted, SystemConsts.NOT_DELETED);
        List<TemplateParam> params = this.list(queryWrapper);
        if (params.isEmpty()) {
            return;
        }
        List<TemplateParam> updateParamList = params.stream().peek(param -> {
            param.setIsDeleted(true);
            param.setModifiedBy(baseReqObj.getOperationUserId());
            param.setGmtModified(LocalDateTime.now());
            // 如果是表格，将表格的参数一并删除
            if (TemplateParamTypeEnum.TABLE.getCode().equals(param.getType())) {
                templateTableParamModel.deleteTeplateTableParamsByTableId(param.getId(), baseReqObj);
            }
        }).collect(Collectors.toList());
        this.updateBatchById(updateParamList);
    }

    /**
     * 获取模板中合约编号参数
     *
     * @param templateId 模板 id
     * @return 合约编号参数对象
     */
    public TemplateParam getContractNo(Integer templateId) {
        LambdaQueryWrapper<TemplateParam> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TemplateParam::getTemplateId, templateId);
        queryWrapper.eq(TemplateParam::getIsDeleted, SystemConsts.NOT_DELETED);
        queryWrapper.eq(TemplateParam::getType, TemplateParamTypeEnum.CONTRACT_NO.getCode());
        return this.getOne(queryWrapper);
    }

    /**
     * 获取模板中合约编号二维码参数
     *
     * @param templateId 模板 id
     * @return 合约编号二维码参数对象
     */
    public TemplateParam getContractNoQrCode(Integer templateId) {
        LambdaQueryWrapper<TemplateParam> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TemplateParam::getTemplateId, templateId);
        queryWrapper.eq(TemplateParam::getType, TemplateParamTypeEnum.CONTRACT_NO_QR_CODE.getCode());
        queryWrapper.eq(TemplateParam::getIsDeleted, SystemConsts.NOT_DELETED);
        return this.getOne(queryWrapper);
    }

    /**
     * 根据模板 id 获取合约编号参数名 <br />
     *
     * @param templateId 模板 id
     * @return 合约编号参数名
     */
    public String getContractNoName(Integer templateId) {
        TemplateParam param = getContractNo(templateId);
        return param == null ? null : param.getParamName();
    }

    /**
     * 根据模板 id 获取合约编号参数名
     *
     * @param templateId 模板 id
     * @return 合约编号参数名
     */
    public String getContractNoQrCodeName(Integer templateId) {
        TemplateParam param = getContractNoQrCode(templateId);
        return param == null ? null : param.getParamName();
    }

}
